/**
 * 高性能POI渲染器 - 使用Cesium原生渲染管线
 * 用于在Cesium中高效渲染大量矢量瓦片POI标签
 */

import * as Cesium from 'cesium';
import { CesiumCollisionIndex } from './cesiumCollisionSystem.js';

/**
 * POI数据类型定义
 */
const POI_TYPES = {
  RESTAURANT: 'restaurant',
  SHOP: 'shop',
  ATTRACTION: 'attraction',
  HOTEL: 'hotel',
  GAS_STATION: 'gas_station',
  HOSPITAL: 'hospital',
  SCHOOL: 'school',
  BANK: 'bank'
};

/**
 * POI样式配置 - Mapbox风格标签
 */
const POI_STYLES = {
  [POI_TYPES.RESTAURANT]: {
    priority: 3,
    minZoom: 3,
    fontSize: 14,
    font: 'bold 14px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.SHOP]: {
    priority: 2,
    minZoom: 4,
    fontSize: 13,
    font: '600 13px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.ATTRACTION]: {
    priority: 5,
    minZoom: 1,
    fontSize: 16,
    font: 'bold 16px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.HOTEL]: {
    priority: 4,
    minZoom: 2,
    fontSize: 14,
    font: '600 14px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.GAS_STATION]: {
    priority: 3,
    minZoom: 3,
    fontSize: 14,
    font: '600 14px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.HOSPITAL]: {
    priority: 6,
    minZoom: 1,
    fontSize: 15,
    font: 'bold 15px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.SCHOOL]: {
    priority: 4,
    minZoom: 2,
    fontSize: 14,
    font: '600 14px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  },
  [POI_TYPES.BANK]: {
    priority: 5,
    minZoom: 2,
    fontSize: 14,
    font: '600 14px "SF Pro Display", "Helvetica Neue", Arial, sans-serif'
  }
};

/**
 * 高性能POI渲染器类
 */
class POIRenderer {
  constructor(viewer, options = {}) {
    this.viewer = viewer;
    this.camera = viewer.camera;
    this.scene = viewer.scene;

    // 等待场景准备就绪
    if (!this.scene || !this.scene.primitives) {
      throw new Error('场景未准备就绪，无法初始化POI渲染器');
    }

    // 初始化碰撞检测系统
    this.collisionIndex = new CesiumCollisionIndex(viewer);

    // 配置选项
    this.options = {
      enableCollisionDetection: true,
      maxPOIsPerTile: 10000, // 大幅增加处理数量
      fadeInDuration: 600, // 淡入动画时长 - 更长的渐进显示
      fadeOutDuration: 300, // 淡出动画时长 - 快速隐藏
      fadeOutDelay: 30, // 淡出延迟进一步减少
      animationEasing: 'easeOutCubic', // 动画缓动函数
      debugMode: true, // 临时开启调试模式
      ...options
    };

    // 创建高性能标签集合
    this.labelCollection = new Cesium.LabelCollection();
    this.scene.primitives.add(this.labelCollection);

    // POI数据容器
    this.poiData = [];
    this.labels = new Map(); // label ID -> {label, poi, style}
    this.visibleLabels = new Set();
    this.animatingLabels = new Map(); // 正在动画的标签 ID -> {animation, targetState}
    this.labelStates = new Map(); // 标签状态 ID -> {visible, alpha, lastUpdate}

    // 相机移动状态
    this._isMoving = false;

    // 性能统计
    this.stats = {
      totalPOIs: 0,
      visiblePOIs: 0,
      culledByCollision: 0,
      culledByZoom: 0,
      renderTime: 0
    };

    this._setupEventHandlers();
    this._startAnimationLoop();
  }

  /**
   * 缓动函数
   */
  _easeOutCubic (t) {
    return 1 - Math.pow(1 - t, 3);
  }

  _easeInOutCubic (t) {
    return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
  }

  // 淡入动画：从慢到快的弹性效果
  _easeOutBack (t) {
    const c1 = 1.70158;
    const c3 = c1 + 1;
    return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
  }

  // 淡入动画：优雅的弹出效果
  _easeOutElastic (t) {
    const c4 = (2 * Math.PI) / 3;
    return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
  }

  // 淡入动画：平滑的加速效果
  _easeOutQuart (t) {
    return 1 - Math.pow(1 - t, 4);
  }

  // 淡出动画：快速线性消失
  _easeInQuart (t) {
    return t * t * t * t;
  }

  /**
   * 启动动画循环
   */
  _startAnimationLoop () {
    const animate = () => {
      this._updateAnimations();
      this._animationFrame = requestAnimationFrame(animate);
    };
    animate();
  }

  /**
   * 更新动画
   */
  _updateAnimations () {
    const currentTime = Date.now();
    const completedAnimations = [];

    for (const [labelId, animationInfo] of this.animatingLabels) {
      const { startTime, duration, startAlpha, targetAlpha, labelInfo, isShow } = animationInfo;
      const elapsed = currentTime - startTime;

      // 如果还在延迟期，跳过
      if (elapsed < 0) {
        continue;
      }

      const progress = Math.min(elapsed / duration, 1);

      // 根据动画类型选择不同的缓动函数
      let easedProgress;
      if (isShow) {
        // 淡入使用平滑的渐进效果
        easedProgress = this._easeOutQuart(progress);
      } else {
        // 淡出使用快速线性消失
        easedProgress = progress * progress; // 二次方加速
      }

      const currentAlpha = startAlpha + (targetAlpha - startAlpha) * easedProgress;

      // 更新标签透明度 - Mapbox风格
      if (labelInfo && labelInfo.label) {
        const label = labelInfo.label;

        // 白色文字透明度
        if (label._originalFillColor) {
          label.fillColor = label._originalFillColor.withAlpha(currentAlpha);
        }

        // 黑色描边透明度
        if (label._originalOutlineColor) {
          label.outlineColor = label._originalOutlineColor.withAlpha(currentAlpha);
        }

        // 控制显示状态
        label.show = currentAlpha > 0;
      }

      // 动画完成
      if (progress >= 1) {
        completedAnimations.push(labelId);

        // 确保最终状态正确设置
        if (labelInfo && labelInfo.label) {
          const label = labelInfo.label;
          if (targetAlpha <= 0) {
            // 淡出完成，直接隐藏标签
            label.show = false;
          } else {
            // 淡入完成，确保完全显示 - Mapbox风格
            label.show = true;
            label.fillColor = label._originalFillColor.withAlpha(1);
            label.outlineColor = label._originalOutlineColor.withAlpha(1);
          }
        }

        // 更新标签状态
        this.labelStates.set(labelId, {
          visible: targetAlpha > 0.5,
          alpha: targetAlpha,
          lastUpdate: currentTime,
          animating: false // 清除动画状态
        });
      }
    }

    // 清理完成的动画
    for (const labelId of completedAnimations) {
      this.animatingLabels.delete(labelId);
    }
  }

  /**
   * 开始标签动画
   */
  _animateLabel (labelId, labelInfo, targetVisible) {
    const currentTime = Date.now();
    const currentState = this.labelStates.get(labelId) || { visible: false, alpha: 0, lastUpdate: currentTime };

    const targetAlpha = targetVisible ? 1.0 : 0.0;

    // 检查是否已经有相同目标的动画在进行
    const existingAnimation = this.animatingLabels.get(labelId);
    if (existingAnimation && existingAnimation.isShow === targetVisible) {
      // 已经在执行相同方向的动画，不重复触发
      return;
    }

    // 如果已经在目标状态，不需要动画
    if (Math.abs(targetAlpha - currentState.alpha) < 0.01) {
      return;
    }

    // 获取当前实际透明度（如果有动画在进行，使用动画中的当前值）
    let startAlpha = currentState.alpha;
    if (existingAnimation) {
      const elapsed = currentTime - existingAnimation.startTime;
      if (elapsed >= 0) {
        const progress = Math.min(elapsed / existingAnimation.duration, 1);
        const easedProgress = existingAnimation.isShow ?
          this._easeOutQuart(progress) :
          progress * progress;
        startAlpha = existingAnimation.startAlpha +
          (existingAnimation.targetAlpha - existingAnimation.startAlpha) * easedProgress;
      } else {
        startAlpha = existingAnimation.startAlpha;
      }
    }

    // 取消现有动画
    if (this.animatingLabels.has(labelId)) {
      this.animatingLabels.delete(labelId);
    }

    // 选择动画时长和延迟
    const duration = targetVisible ? this.options.fadeInDuration : this.options.fadeOutDuration;
    const delay = targetVisible ? 0 : this.options.fadeOutDelay;

    // 开始新动画
    this.animatingLabels.set(labelId, {
      startTime: currentTime + delay,
      duration: duration,
      startAlpha: startAlpha,
      targetAlpha: targetAlpha,
      labelInfo: labelInfo,
      isShow: targetVisible // 记录是淡入还是淡出
    });

    // 立即更新状态，防止重复触发
    this.labelStates.set(labelId, {
      visible: targetVisible,
      alpha: startAlpha,
      lastUpdate: currentTime,
      animating: true
    });

    // 立即显示标签（如果是淡入）
    if (targetVisible && labelInfo.label) {
      labelInfo.label.show = true;
    }
  }

  /**
   * 添加POI数据
   */
  addPOIs (poiData, tileInfo = {}) {
    const startTime = performance.now();

    // 重置统计数据
    this.stats.culledByZoom = 0;
    this.stats.culledByCollision = 0;

    // 清空之前的数据
    this.clearPOIs();

    // 存储POI数据
    this.poiData = poiData;

    // 统计POI类型分布
    const typeStats = {};
    poiData.forEach(poi => {
      typeStats[poi.type] = (typeStats[poi.type] || 0) + 1;
    });
    console.log('POI类型分布:', typeStats);

    // 按优先级排序POI
    const sortedPOIs = this._sortPOIsByPriority(poiData);

    // 当前缩放级别
    const currentZoom = this._getCurrentZoomLevel();

    // 输出相机高度信息
    const height = this.camera.positionCartographic.height;
    console.log(`相机高度: ${height.toFixed(0)}m, 计算的缩放级别: ${currentZoom.toFixed(1)}`);

    // 批量创建标签
    let processedCount = 0;
    let createdCount = 0;

    for (const poi of sortedPOIs) {
      const style = this._getPOIStyle(poi);
      if (!style) {
        processedCount++;
        continue;
      }

      // 创建标签（不管是否可见，先全部创建）
      const label = this._createLabel(poi, style);
      if (label) {
        // 使用自定义ID而不是label.id，避免ID冲突
        const customId = `poi_${processedCount}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
        this.labels.set(customId, {
          label: label,
          poi: poi,
          style: style
        });
        // 为标签添加自定义ID
        label.customId = customId;
        createdCount++;
      }

      processedCount++;
    }

    // 执行碰撞检测和可见性更新
    this._updateCollisionDetectionRealtime();

    this.stats.renderTime = performance.now() - startTime;
    this.stats.totalPOIs = createdCount;

    console.log(`POI渲染完成: 原始数据${poiData.length}, 创建标签${createdCount}, 存储的标签${this.labels.size}, 用时${this.stats.renderTime.toFixed(2)}ms`);
  }

  /**
   * 创建高性能标签
   */
  _createLabel (poi, style) {
    const position = Cesium.Cartesian3.fromDegrees(
      poi.longitude,
      poi.latitude,
      poi.height || 0
    );

    const text = poi.name || '';
    if (!text) return null;

    const label = this.labelCollection.add({
      position: position,
      text: text,
      font: style.font,
      fillColor: Cesium.Color.WHITE.withAlpha(0), // 白色文字，初始透明
      showBackground: false, // 不显示背景
      pixelOffset: new Cesium.Cartesian2(0, 0),
      horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
      verticalOrigin: Cesium.VerticalOrigin.CENTER,
      // disableDepthTestDistance: Number.POSITIVE_INFINITY,
      // Mapbox风格的白色描边 - 更犀利的描边
      outlineColor: Cesium.Color.BLACK.withAlpha(0), // 黑色描边，初始透明
      outlineWidth: 3, // 更粗的描边，让字体更犀利
      style: Cesium.LabelStyle.FILL_AND_OUTLINE,
      show: false // 初始隐藏，通过动画控制显示
    });

    // 存储原始颜色用于动画
    label._originalFillColor = Cesium.Color.WHITE;
    label._originalOutlineColor = Cesium.Color.BLACK;

    // 初始化字体大小缓存，避免首次更新闪烁
    label._currentFontSize = style.fontSize;

    // 添加自定义属性
    label.poiData = poi;
    label.poiType = poi.type;

    return label;
  }

  /**
   * 实时更新碰撞检测
   */
  _updateCollisionDetectionRealtime () {
    if (!this.options.enableCollisionDetection || this.labels.size === 0) {
      // 如果不启用碰撞检测，显示所有标签
      for (const labelInfo of this.labels.values()) {
        const currentZoom = this._getCurrentZoomLevel();
        labelInfo.label.show = currentZoom >= labelInfo.style.minZoom;
      }
      return;
    }

    // 开始正常的碰撞检测流程

    const startTime = performance.now();

    // 清空碰撞检测器
    this.collisionIndex.clearCollisions();

    // 当前缩放级别
    const currentZoom = this._getCurrentZoomLevel();
    console.log(`当前缩放级别: ${currentZoom.toFixed(2)}`);

    // 重置统计
    this.stats.culledByCollision = 0;
    this.stats.culledByZoom = 0;

    let visibleCount = 0;
    let offscreenCount = 0;
    let debugCount = 0;

    // 按优先级排序标签
    const sortedLabels = Array.from(this.labels.values()).sort((a, b) => {
      return b.style.priority - a.style.priority;
    });

    for (const labelInfo of sortedLabels) {
      const { label, poi, style } = labelInfo;

      // 检查缩放级别
      if (currentZoom < style.minZoom) {
        label.show = false;
        this.stats.culledByZoom++;
        continue;
      }

      // 使用固定的字体大小，不随缩放变化
      const newFontSize = style.fontSize;

      // 只在字体大小发生变化时才更新
      const currentFontSize = label._currentFontSize || 0;

      if (newFontSize !== currentFontSize) {
        label.font = style.font.replace(/\d+px/, `${newFontSize}px`);
        label._currentFontSize = newFontSize;
      }

      // 碰撞检测
      const position = Cesium.Cartographic.fromDegrees(
        poi.longitude,
        poi.latitude,
        poi.height || 0
      );

      // 更准确的标签尺寸估算（减少过度保守的估算）
      const text = poi.name || '';
      const estimatedWidth = Math.max(text.length * newFontSize * 0.6, newFontSize * 2);
      const labelSize = {
        width: estimatedWidth + 8, // 减少背景padding
        height: newFontSize + 6 // 减少背景padding
      };

      const placementResult = this.collisionIndex.placeCollisionBox(position, labelSize, {
        allowOverlap: false,
        scale: 1, // 固定缩放比例
        padding: 8, // 减少padding，避免过度严格的碰撞检测
        priority: style.priority,
        groupId: this._getGroupId(poi.type)
      });

      const labelId = label.customId || label.id;
      const currentState = this.labelStates.get(labelId);

      if (placementResult.placed) {
        // 只有当标签不可见或者没有正在进行显示动画时才触发动画
        if (!currentState || !currentState.visible ||
          (currentState.animating && !this.animatingLabels.get(labelId)?.isShow)) {
          this._animateLabel(labelId, labelInfo, true);
        }
        this.visibleLabels.add(labelId);
        visibleCount++;
      } else {
        // 只有当标签可见或者没有正在进行隐藏动画时才触发动画
        if (!currentState || currentState.visible ||
          (currentState.animating && this.animatingLabels.get(labelId)?.isShow)) {
          this._animateLabel(labelId, labelInfo, false);
        }
        this.visibleLabels.delete(labelId);
        if (placementResult.reason === 'offscreen') {
          offscreenCount++;
        } else {
          this.stats.culledByCollision++;
        }
      }
    }

    this.stats.visiblePOIs = visibleCount;
    this.stats.renderTime = performance.now() - startTime;

    // 输出碰撞检测结果
    console.log(`碰撞检测完成: 总标签${sortedLabels.length}, 可见${visibleCount}, 碰撞剔除${this.stats.culledByCollision}, 缩放剔除${this.stats.culledByZoom}, 屏幕外${offscreenCount}, 用时${this.stats.renderTime.toFixed(1)}ms`);

    if (this.options.debugMode) {
      // 输出画布信息
      const canvasInfo = this.collisionIndex.getStats();
      console.log(`画布信息: ${canvasInfo.canvasSize}, 网格: ${canvasInfo.gridSize}, 碰撞盒数量: ${canvasInfo.boxCount}`);

      // 计算可见率
      const visibilityRate = ((visibleCount / sortedLabels.length) * 100).toFixed(1);
      console.log(`标签可见率: ${visibilityRate}%`);
    }
  }

  /**
   * 清空所有POI
   */
  clearPOIs () {
    this.labelCollection.removeAll();
    this.labels.clear();
    this.visibleLabels.clear();
    this.animatingLabels.clear();
    this.labelStates.clear();
    this.collisionIndex.clearCollisions();

    // 重置统计
    this.stats = {
      totalPOIs: 0,
      visiblePOIs: 0,
      culledByCollision: 0,
      culledByZoom: 0,
      renderTime: 0
    };
  }

  /**
   * 设置事件处理器
   */
  _setupEventHandlers () {
    // 相机移动时实时更新碰撞检测
    let updateTimer = null;
    this.camera.changed.addEventListener(() => {
      // 如果正在移动，使用更长的延迟减少频繁更新
      const delay = this._isMoving ? 200 : 100;

      // 防抖处理，避免过于频繁的更新
      if (updateTimer) {
        clearTimeout(updateTimer);
      }

      updateTimer = setTimeout(() => {
        this._updateCollisionDetectionRealtime();
      }, delay);
    });

    // 相机移动开始时的处理
    this.camera.moveStart.addEventListener(() => {
      this._isMoving = true;
    });

    // 相机移动结束时的处理
    this.camera.moveEnd.addEventListener(() => {
      this._isMoving = false;
      // 移动结束后立即更新一次
      setTimeout(() => {
        this._updateCollisionDetectionRealtime();
      }, 50);
    });

    // 点击事件（需要手动实现拾取）
    this.viewer.cesiumWidget.screenSpaceEventHandler.setInputAction((event) => {
      try {
        const picked = this.scene.pick(event.position);
        if (picked && picked.primitive === this.labelCollection) {
          const label = picked.id;
          if (label && label.poiData) {
            this._onPOIClick(label.poiData, label);
          }
        }
      } catch (error) {
        console.warn('点击事件处理失败:', error);
      }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
  }

  /**
   * POI点击事件处理
   */
  _onPOIClick (poiData, label) {
    console.log('POI clicked:', poiData);

    // 相机飞行到POI位置
    this.viewer.camera.flyTo({
      destination: label.position,
      offset: new Cesium.HeadingPitchRange(0, -Math.PI / 4, 1000)
    });
  }

  /**
   * 按优先级排序POI
   */
  _sortPOIsByPriority (poiData) {
    return poiData.sort((a, b) => {
      const styleA = this._getPOIStyle(a);
      const styleB = this._getPOIStyle(b);
      const priorityA = styleA ? styleA.priority : 0;
      const priorityB = styleB ? styleB.priority : 0;
      return priorityB - priorityA; // 优先级高的排在前面
    });
  }

  /**
   * 获取POI样式
   */
  _getPOIStyle (poi) {
    const style = POI_STYLES[poi.type];
    if (!style) {
      console.log(`未找到POI类型 "${poi.type}" 的样式，使用默认样式`);
      return POI_STYLES[POI_TYPES.SHOP];
    }
    return style;
  }



  /**
   * 获取当前缩放级别
   */
  _getCurrentZoomLevel () {
    const height = this.camera.positionCartographic.height;
    // 简化的缩放级别计算
    return Math.max(1, Math.min(20, Math.log2(40075000 / height) + 1));
  }

  /**
   * 获取碰撞组ID
   * 所有标签使用同一个组ID，确保它们互相进行碰撞检测
   */
  _getGroupId (poiType) {
    // 所有POI使用同一个组ID，这样它们会互相碰撞检测
    return 0;
  }

  /**
   * 获取渲染统计
   */
  getStats () {
    return {
      ...this.stats,
      collision: this.collisionIndex.getStats()
    };
  }

  /**
   * 销毁渲染器
   */
  destroy () {
    this.clearPOIs();

    // 停止动画循环
    if (this._animationFrame) {
      cancelAnimationFrame(this._animationFrame);
    }

    if (this.labelCollection) {
      this.scene.primitives.remove(this.labelCollection);
      this.labelCollection = null;
    }

    // 清理事件监听器 - Cesium的事件监听器会自动清理，无需手动移除
    this.viewer = null;
    this.camera = null;
    this.scene = null;
  }
}

export { POIRenderer, POI_TYPES, POI_STYLES }; 